#pragma once

#include <CollisionEntity.h>
#include <vector>
#include <list>
#include <SDL/SDL.h>
#include <iostream>
#include <queue>
#include <stack>
#include <QuadTree.h>
#include <Navmesh.h>
#include <Static.hpp>
class Mesh2D
{
public:
    int *data;
    int meshWidth;
    int meshHeight;
    int cellSize;
};
struct MeshNode
{
    int x, y;
    int h;
    int g;
    int cost;
    MeshNode *parent;
    inline MeshNode(int x, int y, int g, int h, MeshNode *parent) : x(x), y(y), parent(parent)
    {
        this->g = g;
        this->h = h;
        cost = g + h;
    };
};
struct compare
{
    bool operator()(MeshNode *a, MeshNode *b)
    {
        return a->cost > b->cost;
    }
};

class Collision
{
public:
    CollisionEntity *a, *b;
    Vector2 direct;
    bool solved;
};
class CollisionManagement
{
private:
    std::list<CollisionEntity *> collsionEntities_list;
    std::list<Collision *> collisisons_list;
    QuadTree *qtree = nullptr;
    Mesh2D mesh;
    bool meshChange = false;
    Navmesh navmesh;
    bool isRebuildNavmesh = false;

public:
    CollisionManagement();
    ~CollisionManagement();

    const std::list<Collision *> *updateCollisions();
    void add(CollisionEntity *entity);
    bool collide(CollisionEntity *a, std::list<CollisionEntity *> *list = nullptr);
    std::vector<Vector2> findPath(CollisionEntity *entity, Vector2 target) const;
    int *generateMesh(Vector2 ul, int mesh_wsize, int mesh_hsize, int meshCell);
    bool contactMesh(Vector2 pos, int meshSize);
    const std::list<Collision *> *getCollisions();
    std::stack<std::pair<int, int>> getPath_astar(int *mesh, int meshWidth, int meshHeight, int startX, int startY, int targetX, int targetY);
    std::stack<Vector2> getPath_astar(CollisionEntity *entity, int targetX, int targetY) const;
    void generateQuadTree(const CollisionEntityRectangle &rect, int objects_max = 8, int deep_max = 5);
    void updateQuadTree();
    QuadTree *getQuadTree() const;
    void freeQuadTree();
    static int iteratorCount;
    const std::list<CollisionEntity *> *getCollisionEntities() const;
    const Mesh2D *getMesh() const;
    void updateMesh();
    std::vector<int> getCollisionEntityMeshCellIndex(CollisionEntity *entity) const;
    Navmesh *getNavmesh();
    const std::vector<Edge *> *getEdge() const;
    void rebuildNavmesh();
private:
    void _rebuildNavmesh();
};